[网络流24题]最小路径覆盖问题

2020-01-30
网络流24题

题意

用几条链覆盖有向图,链之间不能重叠,求最小的个数并输出方案

题解

构造二层的网络跑最大流即可,答案没问题

构造方案的时候根据$2i+1$->$T$的流量找到链头,再根据中间的流量构造即可

好久之前写了个错的代码,测试过了,数据差评

调试记录

更改构造方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <cstdio>
#include <queue>
#include <cstring>
const int maxn = 12005;
const int INF = 0x3f3f3f3f;
using namespace std;
struct E{
int to, nxt, f;
}e[maxn << 1];
int head[maxn], tot = 1;
void addedge(int u, int v, int f){
e[++tot].to = v, e[tot].nxt = head[u], e[tot].f = f;
head[u] = tot;
}
void ins(int u, int v, int f){
addedge(u, v, f);
addedge(v, u, 0);
}
int dep[maxn], now[maxn], T;
bool bfs(){
queue <int> q; while (!q.empty()) q.pop();
q.push(0); memset(dep, 0, sizeof dep); dep[0] = 1;
memcpy(now, head, sizeof now);
while (!q.empty()){
int cur = q.front(); q.pop();
for (int i = head[cur]; i; i = e[i].nxt)
if (!dep[e[i].to] && e[i].f){
dep[e[i].to] = dep[cur] + 1;
q.push(e[i].to);
}
}
return dep[T];
}
int upper[maxn];
int dfs(int cur, int Max){
if (cur == T) return Max;
int flow = 0;
for (int i = now[cur]; i; i = e[i].nxt){
now[cur] = i;
if (flow >= Max) return flow;
if (dep[e[i].to] == dep[cur] + 1 && e[i].f){
int tmp = dfs(e[i].to, min(Max - flow, e[i].f));
if (tmp == 0) continue;
e[i].f -= tmp;
e[i ^ 1].f += tmp;
flow += tmp;
}
}
return flow;
}
int maxflow = 0;
void Dinic(){
while (bfs())
maxflow += dfs(0, INF);
}
int n, m, res[maxn], last[maxn];
bool vis[maxn];
int main(){
scanf("%d%d", &n, &m);
for (int u, v, i = 1; i <= m; i++){
scanf("%d%d", &u, &v);
ins(u << 1, v << 1 | 1, 1);
} T = n * 2 + 2;
for (int i = 1; i <= n; i++) ins(0, i << 1, 1), ins(i << 1 | 1, T, 1), last[i] = tot - 1;
Dinic();
int ans = n - maxflow;
for (int i = 1; i <= n; i++){
if (vis[i] || e[last[i]].f == 0) continue;
int cur = i << 1;
while (1){
vis[cur >> 1] = 1; bool f = 0; printf("%d ", cur >> 1);
for (int j = head[cur]; j; j = e[j].nxt)
if (e[j].f == 0 && e[j].to != 0) f = 1, cur = e[j].to - 1;
if (!f) break;
} puts("");
}
printf("%d\n", ans);
return 0;
}